#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/time.h>
#include <sys/times.h>
#include <sys/resource.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include "./signaler.h"
#include "./functionHandler.h"
#include "./sem/sem.h"

#define TRUE 0x1
#define FALSE 0x0
#define FILENAME "./logTimes"
//#define unsigned int booly;
static unsigned int automateStat=1;
static pid_t automateSpawnPid;
static info_s funcHandler;
static int semid;
//#define 
enum SIGLIST {sigchld=0,sigusr1=1}signals;
enum NANOSEC {OCTSEC=125000};

int functionRunner(void (*funcToRun)(void*));
int setSignalerHandler(int signo,void (*sasigaction)(int, siginfo_t *info, void *context))
{
	struct sigaction act,oldact;
	act.sa_mask=oldact.sa_mask;
	act.sa_flags = SA_SIGINFO;
  	sigfillset(&act.sa_mask);
  	sigdelset(&act.sa_mask,signo);
  	sigdelset(&act.sa_mask,SIGCHLD);
  	sigprocmask(SIG_BLOCK,&(act.sa_mask),NULL);
 	act.sa_sigaction = sasigaction;
  	return sigaction (signo, &act, NULL);
}

void rootSigintHandler(int signo,siginfo_t *info,void *context);
void sigchldHandler(int signo,siginfo_t *info,void *context);
void sigusr1Handler(int signo,siginfo_t *info,void *context);
void sigusr2Handler(int signo,siginfo_t *info,void *context);
int main(int argc,char*argv[],char*envp[])
{
	pid_t childPid;
	struct sigaction act;
	int key,status;
	FILE* summarize;
	
	if(NULL==(summarize=fopen(FILENAME,"w")))
	{
		perror("fopen");
		exit(2);
	}
	fclose(summarize);
	key = ftok (argv[0], getpid ());
  /* grab the semaphore set created by seminit.c: */
	if ((semid = initSem (key, 1)) == -1)
    {
      perror ("initsem");
      exit (1);
    }
	if(0==(automateSpawnPid=(childPid=fork())))
	{
		spawn();
		exit (1);
	}
	else if (-1==childPid)
	{
		perror("main:fork");
		exit (1);	
	}
	else
	{
		act.sa_flags = SA_SIGINFO;
//	  	sigfillset(&act.sa_mask);
//	  	sigdelset(&act.sa_mask,SIGUSR1);
//	  	sigdelset(&act.sa_mask,SIGCHLD);
// 	 	sigprocmask(SIG_BLOCK,&(act.sa_mask),NULL);
 		act.sa_sigaction = sigusr1Handler;
  		sigaction (SIGUSR1, &act, NULL);
 		act.sa_sigaction = sigusr2Handler;
  		sigaction (SIGUSR2, &act, NULL);
//  	sigaddset(&act.sa_mask,SIGUSR1);
// 		sigprocmask(SIG_BLOCK,&(act.sa_mask),NULL);
  		act.sa_sigaction = sigchldHandler;
  		sigaction (SIGCHLD, &act, NULL);
  		act.sa_sigaction = rootSigintHandler;
  		sigaction (SIGINT, &act, NULL);
		while(automateStat)
		{
			pause();
			if(funcHandler.func){
				functionRunner(funcHandler.func);
				freeSem(semid);
			}
		}
	}
	fprintf(stdout,"cleanup\n");
	while(0<(childPid=waitpid(-1,&status,WNOHANG)))
		fprintf(stdout,"collect child no':%d return value:%d\n",childPid,status);
	removeSem(semid);
	return 0;
}

void rootSigintHandler(int signo,siginfo_t *info,void *context)
{
	kill(automateSpawnPid,SIGINT);
	//kill(getpid(),SIGINT);
	automateStat=0;
	funcHandler.func=NULL;
	
}
int functionRunner(void (*funcToRun)(void*))
{
	int childPid,errNumber;
	struct sigaction act;
	info_s funcHand=funcHandler; /*need to check copy con't memcopy sizeof info_s*/
	if(0==(childPid=fork()))
	{
		char buff[256]={'\0'};
		FILE* fd;
		clock_t start,end;
		struct tms buf;
		act.sa_flags = 0;
		act.sa_handler = SIG_IGN;
		sigaction (SIGUSR1, &act, NULL);
		sigaction (SIGCHLD, &act, NULL);
#ifdef DEBUG
		fprintf(stdout,"invok function runner process:%d\n",getpid());
#endif
//		setitimer(ITIMER_PROF,&funcHand.intervalTimeAndVal,NULL);
		if(-1==setrlimit(RLIMIT_CPU,&funcHand.funcRLimit))
		{perror("functionRunner");exit(2);}
		start=times(&buf);
		funcToRun((void*)&funcHand);
		end=times(&buf);
		sprintf(buff,"process ID:%d run for%e\n",getpid(),(double)(end-start)/sysconf(_SC_CLK_TCK));
		while(NULL==(fd=fopen(FILENAME,"a")))
		{
			errNumber=errno;
			if(errNumber == EACCES || errNumber == EAGAIN)
			{
				usleep(OCTSEC*4);
				continue;
			}
			else
			{
				errno=errNumber;
				perror("fopen");
				_exit(1);
			}
		}
		flockfile(fd);
		fprintf(fd,"%s",buff);
		funlockfile(fd);
		fclose(fd);
		exit (1);
	}
	else if (-1==childPid)
	{
		perror("main:fork");	
	}
	return childPid;
}

void sigusr1Handler(int signo,siginfo_t *info,void *context)
{
	int lockStat,errorNum;
	struct timespec tm;
	tm.tv_nsec=OCTSEC;
	tm.tv_sec=0;
#ifdef DEBUG
	fprintf(stdout,"current pid%d",getpid());
	fprintf(stdout,"SIGUSR1 send pid%d,2:25\n",info->si_pid);
#endif
	if(-1==(lockStat=lockSemTime(semid,tm)))
	{
		errorNum=errno;
		if(EAGAIN==errorNum || EINTR==errorNum){
			/*maybe shold re try*/
			funcHandler.func=functionError;
		}
		else
		{
			funcHandler.func=functionError;
			return;
		}
		
	}
//	funcHandler.intervalTimeAndVal.it_interval.tv_sec=1;
//	funcHandler.intervalTimeAndVal.it_interval.tv_usec=OCTSEC*4;
//	funcHandler.intervalTimeAndVal.it_value.tv_sec=1;
//	funcHandler.intervalTimeAndVal.it_value.tv_sec=0;
	funcHandler.funcRLimit.rlim_cur=1;
	funcHandler.funcRLimit.rlim_max=2;
	funcHandler.func=readString;
}
void sigusr2Handler(int signo,siginfo_t *info,void *context)
{
	int lockStat,errorNum;
	struct timespec tm;
	tm.tv_nsec=OCTSEC;
	tm.tv_sec=0;
#ifdef DEBUG
	fprintf(stdout,"current pid%d",getpid());
	fprintf(stdout,"SIGUSR1 send pid%d,2:25\n",info->si_pid);
#endif
	if(-1==(lockStat=lockSemTime(semid,tm)))
	{
		errorNum=errno;
		if(EAGAIN==errorNum || EINTR==errorNum){
			/*maybe shold re try*/
			funcHandler.func=functionError;
		}
		else
		{
			funcHandler.func=functionError;
			return;
		}
		
	}
	funcHandler.funcRLimit.rlim_cur=1;
	funcHandler.funcRLimit.rlim_max=1;
	funcHandler.func=numberEnumerator;
}

void sigchldHandler(int signo,siginfo_t *info,void *context)
{
	int waitStatus,childReturnVal;
	childReturnVal=waitpid(-1,&waitStatus,WNOHANG);
	if(automateSpawnPid==info->si_pid){
		automateStat=0;
	}
	funcHandler.func=sigChildIgn;
#ifdef DEBUG
	fprintf(stdout,"collect child no':%d return value:%d\n",childReturnVal,waitStatus);
#endif
}
